"use strict"
/**
 * 解析器
 * 1. 初始化页面，解析插值表达式和指令
 * 2. 构建观察者，设置视图更新回调
 * 3. 双向数据绑定，监听用户输入修改表单
 * */ 
class Compiler{
    constructor(vm) {
        this.vm = vm
        
        console.log('this', this)
        // 初始化遍历 dom 解析插值表达式和指令
        this.compilerDocument(this.vm.$el)
    }

    // 编译 dom 
    compilerDocument(el) {
        Array.from(el.childNodes).forEach((nodes) => {
            if (nodes.nodeType ===  1) {
                this.compilerElementNode(nodes)
            } else if (nodes.nodeType === 3) {
                this.compilerTextNode(nodes)
            }

            // 迭代子节点
            if(nodes.childNodes && nodes.childNodes.length > 0) {
                this.compilerDocument(nodes)
            }
        })
    }

    // 处理元素节点
    compilerElementNode(nodes) {
        // 判断是否为指令，并处理指令
        Array.from(nodes.attributes).forEach((attr) => {
            if (this.isDirective(attr.name)) {
                this.compilerDirective(nodes, attr)
            }
        })
        // console.log('元素节点------', nodes.innerHTML)
        // 执行指令对应的方法

    }
    // 处理文本节点
    compilerTextNode(nodes) {
        const exp = /\{\{(.+?)\}\}/g
        let nodesValue = nodes.textContent
        
        if (exp.test(nodesValue)) {
            let key = RegExp.$1.trim()

            // 绑定更新回调
            new Watcher(this.vm, key, (val) => {
                nodes.textContent = nodesValue.replace(exp, val)
            })
        }
    }
    // 是否为指令
    isDirective(attrName) {
        return attrName.startsWith('v-')
    }
    // 编译指令
    compilerDirective(nodes, attr) {
        // 获取指令名称
        const directive = attr.name.substr(2)

        // 执行对应指令的回调
        this[`${directive}Updates`](nodes, directive, attr.value)
    }

    // v-text 的回调
    textUpdates(nodes, directive, attrValue) {
        new Watcher(this.vm, attrValue, (val) => {
            nodes.innerText = val
        })
    }

    // v-html 的回调
    htmlUpdates(nodes, directive, attrValue) {
        new Watcher(this.vm, attrValue, (val) => {
            nodes.innerHTML = val
        })
    }

    // v-model 的回调
    modelUpdates(nodes, directive, attrValue) {
        new Watcher(this.vm, attrValue, (val) => {
            nodes.value = val
        })
        // 双向绑定
        nodes.addEventListener('input', (e) => {
            this.vm[attrValue] = nodes.value
        })
    }

}
